# -*- coding: utf-8 -*-
"""Controlador de Alfabetos"""
from formencode        import validators
from tg import expose, flash, require, url, request, redirect
from pylons.i18n import ugettext as _, lazy_ugettext as l_
from tgext.admin.tgadminconfig import TGAdminConfig
from tgext.admin.controller import AdminController, AdminConfig
from repoze.what import predicates
from tg import tmpl_context, validate
from webhelpers import paginate
from sqlalchemy import func
from sqlalchemy.exc import IntegrityError, SQLAlchemyError
import transaction

from lex.lib.base import BaseController
from lex.model import metadata, DBSession
from lex.model.model import Alfabeto 
from lex import model
from lex.widgets import alfabetos_form
from lex.widgets.alfabetos_form import crear_alfabeto_form, editar_alfabeto_form

__all__ = ['AlfabetosController']

class AlfabetosController(BaseController):
    @expose('lex.templates.alfabetos.listado')    
    def listado(self, **kw):
        return dict()
        #redirect('listado')
    
    @validate(validators={"page":validators.Int(), "rp":validators.Int()})
    @expose('json')
    def datos(self, page='1', rp='25', sortname='nombre', sortorder='asc', qtype=None, query=None):
	  try:
		
		alfabetos = DBSession.query(Alfabeto).order_by(Alfabeto.id_alfabeto)
		
		total = alfabetos.count()
            	#column = getattr(Alfabetos, sortname)
		print "foooooooooooooooo000000000000000000000000000"
		rows = [{'id'  : alfabeto.id_alfabeto,
                        'cell': [alfabeto.id_alfabeto,
			    alfabeto.nombre_alfabeto,
                            alfabeto.definicion_alfabeto]} for alfabeto in alfabetos]
                result = dict(page=page, total=total, rows=rows)
          except:
                result = dict() 
          return result


    @expose('lex.templates.alfabetos.nuevo_alfabeto')
    def nuevo(self, **kw):
        """Despliega el formulario para añadir un nuevo Alfabeto."""
        try:
            #Establecemos el contexto de nuestro formulario de creacion de alfabeto.
            tmpl_context.form = crear_alfabeto_form
        except SQLAlchemyError:
            flash(_("No se pudo acceder a Creacion de Alfabetos! SQLAlchemyError..."), 'error')
            redirect("/alfabetos/listado")
        except (AttributeError, NameError):
            flash(_("No se pudo acceder a Creacion de Alfabeto! Hay Problemas con el servidor..."), 'error')
            redirect("/alfabetos/listado")

        return dict(nombre_modelo='Alfabeto', value=kw)

    @validate(crear_alfabeto_form, error_handler=nuevo)
    @expose()
    def add(self, **kw):
        """Metodo para agregar un registro a la base de datos """
        try:
################################################################################
#Advertencia: Estas validaciones tambien se realizan en la funcion "update". Asi
#que, cualquier cambio realizado aqui, tambien debe considerarse si se realiza o
#no en la funcion "update".
######################### VALIDACION DEL NOMBRE ################################
            #Realizamos algunas comprobaciones del nombre del alfabeto.
            nombre_alfabeto = kw['nombre_alfabeto']
            lista_nombre = nombre_alfabeto.split()
            nombre_alfabeto = " ".join(lista_nombre) #Nombre final del alfabeto.

######################### VALIDACION DE LA DEFINICION ##########################

            #Verificamos la correcta definicion del alfabeto. El alfabeto solo puede
            #constar de simbolos individuales separados entre espacios en blanco.
            #Extraemos todas las subcadenas tomando como delimitador el 
            #espacio en blanco. De cada subcadena solo consideramos el primer caracter,
            #en caso que se hayan introducidos varios.Tambien verificamos que no se hayan 
            #introducido operadores de expresiones regulares como simbolos.
            definicion_alfabeto = kw['definicion_alfabeto']
            lista_definicion = []
            lista_definicion = definicion_alfabeto.split()
            lista_limpia = []

            for subcadena in lista_definicion:
                for sub in subcadena:
                    if sub[0]=="+" or sub[0]=="*" or sub[0]=="?" or sub[0]=="|" or sub[0]=="." or sub[0]=="(" or sub[0]==")":
                       break
                    else:
                       lista_limpia.append(sub)
                       break

            #Eliminamos los duplicados y ordenamos la lista, luego 
            #convertimos la lista en una cadena.
            lista_limpia = list(set(lista_limpia))
            lista_limpia.sort()
            definicion_alfabeto = " ".join(lista_limpia) #Definicion final del alfabeto.

################################################################################

            #Creamos un nuevo alfabeto e insertamos en la BD.
            alfabeto = Alfabeto()
            alfabeto.nombre_alfabeto = nombre_alfabeto
            alfabeto.definicion_alfabeto = definicion_alfabeto
            DBSession.add(alfabeto)

            #Confirmamos la transaccion.
            DBSession.flush()
            transaction.commit()
        except IntegrityError:
            transaction.abort()
            flash(_("No se ha guardado! Hay Problemas con el servidor..."), 'error')
            redirect("/alfabetos/listado")
        except SQLAlchemyError:
            flash(_("No se ha guardado! SQLAlchemyError..."), 'error')
            redirect("/alfabetos/listado")
        except (AttributeError, NameError):
            flash(_("No se ha guardado! Hay Problemas con el servidor..."), 'error')
            redirect("/alfabetos/listado")
        else:
            flash(_("Alfabeto creado!"), 'ok')
    
        redirect("/alfabetos/listado")

    @expose('lex.templates.alfabetos.editar_alfabeto')
    def editar(self, id_alfabeto, **kw):
        """Metodo que rellena el formulario para editar los datos de un Alfabeto"""
        try:
            #Establecemos el contexto del formulario de edicion de alfabetos.
            tmpl_context.form = editar_alfabeto_form

            #Cargamos el formulario con los datos del alfabeto a editar.
            alfabeto = DBSession.query(Alfabeto).get(id_alfabeto)
            kw['id_alfabeto'] = alfabeto.id_alfabeto
            kw['nombre_alfabeto'] = alfabeto.nombre_alfabeto
            kw['definicion_alfabeto'] = alfabeto.definicion_alfabeto
        except SQLAlchemyError:
            flash(_("No se pudo acceder a Edicion de Alfabetos! SQLAlchemyError..."), 'error')
            redirect("/alfabetos/listado")
        except (AttributeError, NameError):
            flash(_("No se pudo acceder a Edicion de Alfabetos! Hay Problemas con el servidor..."), 'error')
            redirect("/alfabetos/listado")

        return dict(value=alfabeto)

    @validate(editar_alfabeto_form, error_handler=editar)
    @expose()
    def update(self, **kw):        
        """Metodo que actualizar la base de datos"""
        try:
################################################################################
#Advertencia: Estas validaciones tambien se realizan en la funcion "add". Asi
#que, cualquier cambio realizado aqui, tambien debe considerarse si se realiza o
#no en la funcion "add".
######################### VALIDACION DEL NOMBRE ################################
            #Realizamos algunas comprobaciones del nombre del alfabeto.
            nombre_alfabeto = kw['nombre_alfabeto']
            lista_nombre = nombre_alfabeto.split()
            nombre_alfabeto = " ".join(lista_nombre) #Nombre final del alfabeto.

######################### VALIDACION DE LA DEFINICION ##########################
            
            #Verificamos la correcta definicion del alfabeto. El alfabeto solo puede
            #constar de simbolos individuales separados entre espacios en blanco.
            #Extraemos todas las subcadenas tomando como delimitador el 
            #espacio en blanco. De cada subcadena solo consideramos el primer caracter,
            #en caso que se hayan introducidos varios.Tambien verificamos que no se hayan 
            #introducido operadores de expresiones regulares como simbolos.
            definicion_alfabeto = kw['definicion_alfabeto']
            lista_definicion = []
            lista_definicion = definicion_alfabeto.split()
            lista_limpia = []

            for subcadena in lista_definicion:
                for sub in subcadena:
                    if sub[0]=="+" or sub[0]=="*" or sub[0]=="?" or sub[0]=="|" or sub[0]=="." or sub[0]=="(" or sub[0]==")":
                       break
                    else:
                       lista_limpia.append(sub)
                       break

            #Eliminamos los duplicados y ordenamos la lista, luego 
            #convertimos la lista en una cadena.
            lista_limpia = list(set(lista_limpia))
            lista_limpia.sort()
            definicion_alfabeto = " ".join(lista_limpia) #Definicion final del alfabeto.

################################################################################

            #Guardamos los cambios realizados en la edicion del alfabeto.
            id_alfabeto = kw['id_alfabeto']
            alfabeto = DBSession.query(Alfabeto).get(id_alfabeto)
            alfabeto.nombre_alfabeto = nombre_alfabeto
            alfabeto.definicion_alfabeto = definicion_alfabeto

            #Confirmamos la transaccion
            DBSession.flush()
            transaction.commit()

################################################################################
#Advertencia: Las siguientes verificaciones tambien se realizan en la funcion 
#"delete". Asi que, cualquier cambio realizado aqui, tambien debe considerarse 
#si se realiza o no en la funcion "delete".
############### VERIFICACION DE LOS ANALIZADORES AFECTADOS #####################

            #Por cada analizador afectado, establecemos a "False" el campo 
            #"validado" de sus expresiones regulares. Tambien establecemos a
            #"False" el campo "estado" de los analizadores afectados.
            alfabeto_editado = DBSession.query(Alfabeto).get(id_alfabeto)
            analizadores_afectados = alfabeto_editado.analizadores_lexicos
            if analizadores_afectados != []:
               for analizador_afectado in analizadores_afectados:
                   expresiones_afectadas = analizador_afectado.expresiones_regulares
                   if expresiones_afectadas != []:
                      for expresion_afectada in expresiones_afectadas:
                          expresion_afectada.validado = False
                   analizador_afectado.estado = False


################################################################################
        except IntegrityError:
            transaction.abort()
            flash(_("No se han guardado los cambios! Hay Problemas con el servidor..."), 'error')
            redirect("/alfabetos/listado")
        except SQLAlchemyError:
            flash(_("No se han guardado los cambios! SQLAlchemyError..."), 'error')
            redirect("/alfabetos/listado")
        except (AttributeError, NameError):
            flash(_("No se han guardado los cambios! Hay Problemas con el servidor..."), 'error')
            redirect("/alfabetos/listado")
        else:
            flash(_("Se han guardado los cambios!"), 'ok')

        redirect("/alfabetos/listado")

    @expose('lex.templates.alfabetos.confirmar_eliminar_alfabeto')
    def confirmar_eliminar_alfabeto(self, id_alfabeto, **kw):
        """Despliega confirmacion de eliminacion"""
        try:
            #Se muestran los datos del alfabeto seleccionado.
            alfabeto = DBSession.query(Alfabeto).get(id_alfabeto)
        except SQLAlchemyError:
            flash(_("No se pudo acceder a Eliminacion de Alfabetos! SQLAlchemyError..."), 'error')
            redirect("/alfabetos/listado")
        except (AttributeError, NameError):
            flash(_("No se pudo acceder a Eliminacion de Alfabetos! Hay Problemas con el servidor..."), 'error')
            redirect("/alfabetos/listado")

        return dict(value=alfabeto)

    @validate(validators={"page":validators.Int(), "rp":validators.Int()})
    @expose('json')
    def delete(self, id_alfabeto, **kw):
        """Metodo que elimina un registro de la base de datos"""
        try:
################################################################################
#Advertencia: Las siguientes verificaciones tambien se realizan en la funcion 
#"update". Asi que, cualquier cambio realizado aqui, tambien debe considerarse 
#si se realiza o no en la funcion "update".
############### VERIFICACION DE LOS ANALIZADORES AFECTADOS #####################

            #Por cada analizador afectado, establecemos a "False" el campo 
            #"validado" de sus expresiones regulares. Tambien establecemos a
            #"False" el campo "estado" de los analizadores afectados.
            alfabeto_a_eliminar = DBSession.query(Alfabeto).get(id_alfabeto)
	    nombre=alfabeto_a_eliminar.nombre_alfabeto
            analizadores_afectados = alfabeto_a_eliminar.analizadores_lexicos
            if analizadores_afectados != []:
               for analizador_afectado in analizadores_afectados:
                   expresiones_afectadas = analizador_afectado.expresiones_regulares
                   if expresiones_afectadas != []:
                      for expresion_afectada in expresiones_afectadas:
                          expresion_afectada.validado = False
                   analizador_afectado.estado = False


################################################################################

            #Eliminamos el alfabeto de la base de datos.
            DBSession.delete(DBSession.query(Alfabeto).get(id_alfabeto))

            #Confirmamos la transaccion.
            DBSession.flush()
            transaction.commit()
        except IntegrityError:
            transaction.abort()
            msg="No se ha eliminado! Hay Problemas con el servidor..."
	    type="error"
            redirect("/alfabetos/listado")
        except SQLAlchemyError:
            msg="No se ha eliminado! SQLAlchemyError..."
	    type="error"
            redirect("/alfabetos/listado")
        except (AttributeError, NameError):
            msg="No se ha eliminado! Hay Problemas con el servidor..."
	    type="error"
            redirect("/alfabetos/listado")
        else:
            msg="El alfabeto se ha eliminado con exito!."
	    type="succes"

        return dict(msg=msg,nombre=nombre,type=type)
